
package taller2.controller.modes.supervisor;

import java.awt.event.MouseEvent;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

import taller2.controller.modes.Mode;
import taller2.interfaces.Connection;
import taller2.interfaces.Graph;
import taller2.interfaces.Node;
import taller2.utils.Constants;
import taller2.utils.Point;
import taller2.view.draws.DrawingArea;
import taller2.view.draws.GraphDrawer;

public class TopologicBfsSupervisorMode implements Mode {
	private Graph graph;
	private Node actual;

	ArrayList<Node> posibleSolutions;
	ArrayList<Integer> incidencias;
	ArrayList<Node> nodes;
	
	private boolean finished;
	
	// constructor
	public TopologicBfsSupervisorMode(Graph graph){
		this.graph = graph;

		this.actual = null;

		this.posibleSolutions = new ArrayList<Node>();
		this.incidencias = new ArrayList<Integer>();
		
		//carga grado de incidencia de los nodos
		nodes = graph.getNodes();

		for(int i=0; i<nodes.size() ; i++){
			//seteo indices desde el 0
			Node node = nodes.get(i);
			node.setId(i);
			//cargo cuantas aristas incidentes tiene cada nodo
			incidencias.add( graph.getConnectionsTo(node).size() );	
			
			//agrego como soluciones iniciales posibles (aka proximo nodo seleccionable por el usuario) a los que tienen cero incidencias
			if (incidencias.get(i) == 0){
				posibleSolutions.add(node);
			}
		}

		
		this.finished = false;
	}
	
	public void whenPressed(MouseEvent arg0, DrawingArea area) {
		GraphDrawer drawer = area.getDrawer();
		Point pos = new Point(arg0.getX(),arg0.getY());
		if(!finished) //finished pasa a true cuando se seleccionan todos los nodos
			supervise(drawer,area,pos);
	}
	
	private void supervise(GraphDrawer drawer, DrawingArea area,Point pos){
		actual = drawer.getCloseByNode(pos);
		//si selecciono un nodo (hizo click cerca)
		if(actual != null)
			processSolution();
		
		//Si termino el recorrido de todo el grafo, le digo muy bien  con un pop up y se acabo.
		if(allNodesSelected()){
			JFrame frame = new JFrame();
			JOptionPane.showMessageDialog(frame,Constants.okMsg);

			finished = true;
		}
				
		selectConnections();
		area.repaint();
	}

	private void processSolution(){
		
		if ( validarNodoElegido(actual) ){
			bajarIncidenciasDesde(actual);
			actual.select();
			//lo saco de las soluciones
			posibleSolutions.remove(actual);
			
			//agrego los que pasan a ser soluciones validas (sin repetir)
			for (Connection connection : actual.getConnections()) {
				Node other = connection.getOtherNode();

				if ((incidencias.get(other.getNumberId()) == 0) && (!posibleSolutions.contains(other)) ){
					posibleSolutions.add(other);
				}
			}
		//si no es valido aviso al usuario que se equivoco
		}else{
			JFrame frame = new JFrame();
			JOptionPane.showMessageDialog(frame,Constants.errorMsgTopo);		
		}
	}
	
	private boolean validarNodoElegido(Node nodo){
		return (nodo == posibleSolutions.get(0));
	}
	
	private void selectConnections(){
		for(Connection conn : graph.getAllConnections().values()){
			Node node = conn.getOtherNode();
			Node node2 = conn.getThisNode();
			if(node.isSelected() && node2.isSelected())
				conn.select();
		}
	}
	
	private boolean allNodesSelected() {
		for(Node node : graph.getNodes()){
			if(!node.isSelected())
				return false;
		}
		return true;
	}
	
	private void bajarIncidenciasDesde(Node nodo){
		for (Connection connection : nodo.getConnections()) {
			Node other = connection.getOtherNode();

			int inci = incidencias.get(other.getNumberId());
			inci --;
			incidencias.set(other.getNumberId(),inci);
		}
	}
	
	public void whenReleased(MouseEvent arg0, DrawingArea area) {}

	public void whenDragged(MouseEvent arg0, DrawingArea area) {}

}
